package com.happyhome.controller;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.imageio.ImageIO;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.imgscalr.Scalr;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;

import com.happyhome.constants.AppConstant;
import com.happyhome.datamodel.District;
import com.happyhome.datamodel.House;
import com.happyhome.datamodel.HouseUtility;
import com.happyhome.datamodel.Image;
import com.happyhome.datamodel.Parameter;
import com.happyhome.datamodel.Province;
import com.happyhome.datamodel.User;
import com.happyhome.datamodel.Utility;
import com.happyhome.services.DistrictService;
import com.happyhome.services.HouseService;
import com.happyhome.services.HouseUtilityService;
import com.happyhome.services.ImageService;
import com.happyhome.services.ParameterService;
import com.happyhome.services.ProvinceService;
import com.happyhome.services.UsersService;
import com.happyhome.services.UtilityService;

@Controller
@RequestMapping("/admin/houses")
public class HouseController {
	
	private static final Logger log = LoggerFactory.getLogger(HouseController.class);
	
	@Autowired
	private ProvinceService provinceService;
	
	@Autowired
	private DistrictService districtService;
	
	@Autowired
	private UsersService usersService;
	
	@Autowired
	private UtilityService utilityService;
	
	@Autowired
	private HouseService houseService;
	
	@Autowired
	private HouseUtilityService houseUtilityService;
	
	@Autowired
	private ImageService imageService;
	
	@Autowired
	private ServletContext context;
	
	@Autowired
	private ParameterService parameterService;
	
	private SimpleDateFormat formatter = new SimpleDateFormat(AppConstant.DATE_FORMAT);
	
	@RequestMapping(value = "/list", method = RequestMethod.GET)
	public ModelAndView login() {
		return new ModelAndView("/admin/houses/list");
	}
	
	/* load data form create new house */ 
	@RequestMapping(value = "/new", method = RequestMethod.GET)
	public ModelAndView newHouse() {
		List<Province> provinces = provinceService.getAllProvinces();
		List<District> districts = districtService.getAllDistricts();
		List<User> users = usersService.getAllUsers();
		List<Utility> utilities = utilityService.getAllUtilities();
		
		ModelAndView model = new ModelAndView("/admin/houses/new");
		
		model.addObject("provinces", provinces);
		model.addObject("districts", districts);
		model.addObject("users", users);
		model.addObject("utilities", utilities);
		return model;
	}
	
	/* form new House submit form */
	@RequestMapping(value = "/newHouseSubmit", method = RequestMethod.POST)
	public @ResponseBody String newHouseSubmit(HttpServletRequest request){
		Map<String, String[]> multiParameters = request.getParameterMap();
		House house = setValueForHouse(null, multiParameters);
		List<Utility> utilities = setUtilities(multiParameters);
		if(house != null){ // input invalid in setValueForHouse
			house = houseService.merge(house);
			if(house != null){
				for(Utility utility :utilities){
					HouseUtility houseUtility = new HouseUtility();
					houseUtility.setHouse(house);
					houseUtility.setUtility(utility);
					houseUtility.setStatus(Boolean.valueOf("true"));
					houseUtilityService.merge(houseUtility);
				}
			}
			return house.getIdHouse() + ";" + house.getNameHouse();
		}
		return "fail";
	}
	
	/* get method upload house's image */
	@RequestMapping(value = "/uploadImages", method = RequestMethod.GET, produces="text/html; charset=utf-8")
	public ModelAndView uploadImages(@RequestParam(value="houseId") String houseId) {
		ModelAndView model = new ModelAndView("admin/houses/uploadImages");
		House house = houseService.findHouseById(Long.parseLong(houseId));
		model.addObject("houseId", house.getIdHouse());
		model.addObject("houseName", house.getNameHouse());
		
		List<Image> images = imageService.getAllImagesByHouseId(Long.parseLong(houseId));
		
		if(images != null && images.size() > 0){
			for(Image image: images){
				image.setUrl("/" + AppConstant.APP_URL + "/admin/picture/"+ image.getId());
	            image.setThumbnailUrl("/" + AppConstant.APP_URL + "/admin/thumbnail/"+ image.getId());
	            image.setDeleteUrl("/" + AppConstant.APP_URL + "/admin/delete/"+ image.getId());
	            image.setDeleteType("DELETE");
	            image.setHouse(null);
			}
		}
		model.addObject("images", images);
		return model;
	}
	
	@RequestMapping(value = "/uploadImages", method = RequestMethod.POST)
    public @ResponseBody Map<String, Object> upload(MultipartHttpServletRequest request, HttpServletResponse response) {
		log.debug("uploadPost called");
        Iterator<String> itr = request.getFileNames();
        MultipartFile mpf;
        List<Image> list = new LinkedList<Image>();
        String houseIdValue = request.getParameter("houseIdValue");
        House house = houseService.findHouseById(Long.parseLong(houseIdValue));
        while (itr.hasNext()) {
            mpf = request.getFile(itr.next());
            log.debug("Uploading {}", mpf.getOriginalFilename());
            
            String newFilenameBase = UUID.randomUUID().toString();
            String originalFileExtension = mpf.getOriginalFilename().substring(mpf.getOriginalFilename().lastIndexOf("."));
            String newFilename = newFilenameBase + originalFileExtension;
            
            String filename = "/WEB-INF" ;
			String pathname = context.getRealPath(filename);
			
			File dir = new File(pathname + File.separator + "images");
			
			if(!dir.exists()){
				dir.mkdirs();
			}
			
            String contentType = mpf.getContentType();
            
            File newFile = new File(dir.getAbsolutePath() + File.separator + newFilename);
            try {
                mpf.transferTo(newFile);
                
                BufferedImage thumbnail = Scalr.resize(ImageIO.read(newFile), 80);
                String thumbnailFilename = newFilenameBase + "-thumbnail.png";
                File thumbnailFile = new File(dir.getAbsolutePath() + File.separator + thumbnailFilename);
                ImageIO.write(thumbnail, "png", thumbnailFile);
                
                Image image = new Image();
                image.setName(mpf.getOriginalFilename());
                image.setThumbnailFilename(thumbnailFilename);
                image.setNewFilename(newFilename);
                image.setContentType(contentType);
                image.setSize(mpf.getSize());
                image.setThumbnailSize(thumbnailFile.length());
                image.setDateCreated(new Date());
                image.setLastUpdated(new Date());
                image.setHouse(house);
                image = imageService.merge(image);
                
                image.setUrl("/" + AppConstant.APP_URL + "/admin/picture/"+ image.getId());
                image.setThumbnailUrl("/" + AppConstant.APP_URL + "/admin/thumbnail/"+ image.getId());
                image.setDeleteUrl("/" + AppConstant.APP_URL + "/admin/delete/"+ image.getId());
                image.setDeleteType("DELETE");
                image.setHouse(null);
                list.add(image);
                
            } catch(IOException e) {
                log.error("Could not upload file " + mpf.getOriginalFilename(), e);
            }
            
        }
        
        Map<String, Object> files = new HashMap<String, Object>();
        files.put("files", list);
        return files;
    }
	
    @RequestMapping(value = "/getData", method = RequestMethod.GET)
    public @ResponseBody List<House> getData() {
    	List<House> listHouses = houseService.getAll();
    	for(House house : listHouses){
    		house.setDistrict(null);
    		house.setHouseUtilities(null);
    		house.setRoomsSet(null);
    		house.setImages(null);
    		house.setManagerName(house.getUser().getFullName());
    		house.setUser(null);
    	}
	    return listHouses;
    }
    
 	// edit product event
 	@RequestMapping(value = "/edit/{houseId}", method = RequestMethod.GET)
 	public ModelAndView editHouse(@PathVariable Long houseId){
 		House house = houseService.findEagerHouseById(houseId);
 		List<Province> provinces = provinceService.getAllProvinces();
		List<User> users = usersService.getAllUsers();
		List<Utility> utilities = utilityService.getAllUtilities();
		District district = house.getDistrict();
		Province province = district.getProvince();
		User user = house.getUser();
		
		List<Object[]> houseUtility = houseUtilityService.getAllUtilityByHouseId(houseId);
		List<Utility> resultCombine = combineUtility(utilities, houseUtility);
		
		ModelAndView model = new ModelAndView("/admin/houses/edit");
		
		model.addObject("provinces", provinces);
		model.addObject("users", users);
		model.addObject("house", house);
		model.addObject("province", province);
		model.addObject("district", district);
		model.addObject("user", user);
		model.addObject("resultCombine", resultCombine);
		
		return model;
 	}
 	
 	@RequestMapping(value = "/edit", method = RequestMethod.POST)
 	public @ResponseBody String saveEditProduct(HttpServletRequest request){
 		Map<String, String[]> multiParameters = request.getParameterMap();
 		// merge product and attribute;
 		if(multiParameters.get("houseId")[0] != null){
 			House houseTarget = houseService.findHouseById(Long.parseLong(multiParameters.get("houseId")[0]));
 			House houseMerge = setValueForHouse(houseTarget, multiParameters);
 			if(houseMerge != null){ // input invalid in setValueForHouse
 				houseMerge = houseService.merge(houseMerge);
	 			houseUtilityService.deleteAllUtilitiesHouseUtility(Long.parseLong(multiParameters.get("houseId")[0]));
	 			List<Utility> utilities = setUtilities(multiParameters);
				for(Utility utility :utilities){
					HouseUtility houseUtility = new HouseUtility();
					houseUtility.setHouse(houseMerge);
					houseUtility.setUtility(utility);
					houseUtility.setStatus(Boolean.valueOf("true"));
					houseUtilityService.merge(houseUtility);
				}
 				return houseMerge.getIdHouse() + ";" + houseMerge.getNameHouse();
 			}
 		}
 		return "fail";
 	}
	
	@RequestMapping(value="/getDistrictByProvinceCode", method = RequestMethod.GET, produces="text/html; charset=utf-8")
	public @ResponseBody String getDistrictByProvinceCode(@RequestParam(value = "provinceCode") String provinceCode) { 
		List<District> districts = districtService.getDistrictByProvinceCode(provinceCode);
		StringBuffer resultString = new StringBuffer();
		if(districts != null && districts.size() > 0){
			for (District district : districts) {
				resultString.append("<option value=\"");
				resultString.append(district.getCodeDistrict());
				resultString.append("\">");
				resultString.append(district.getNameDistrict());
				resultString.append("</option>");
			}
		}
		return resultString.toString();  
	}
	
	private House setValueForHouse(House house, Map<String, String[]> multiParameters){
		if(house == null){
			house = new House();
		}
		
		String[] googleMap = multiParameters.get(AppConstant.GOOGLE_MAP);
		if(googleMap != null ){
			house.setGoogleMap(googleMap[0]);
			multiParameters.remove(AppConstant.GOOGLE_MAP);
		}
		String[] checkInDate = multiParameters.get(AppConstant.CHECK_IN_DATE);
		if(checkInDate != null ){
			try {
				Date inDate = formatter.parse(checkInDate[0]);
				house.setCheckInDate(inDate);
				multiParameters.remove(AppConstant.CHECK_IN_DATE);
			} catch (ParseException e) {
				e.printStackTrace();
				return null;
			}
		}
		String[] checkOutDate = multiParameters.get(AppConstant.CHECK_OUT_DATE);
		if(checkOutDate != null ){
			try {
				Date outDate = formatter.parse(checkOutDate[0]);
				house.setCheckOutDate(outDate);
				multiParameters.remove(AppConstant.CHECK_OUT_DATE);
			} catch (ParseException e) {
				e.printStackTrace();
				return null;
			}
		}
		String[] nameHouse = multiParameters.get(AppConstant.NAMEHOUSE);
		if(nameHouse != null ){
			house.setNameHouse(nameHouse[0]);
			multiParameters.remove(AppConstant.NAMEHOUSE);
		}
		String[] sqft = multiParameters.get(AppConstant.SQFT);
		if(sqft != null ){
			try{
				house.setSqft(Long.parseLong(sqft[0]));
				multiParameters.remove(AppConstant.SQFT);
			}catch(NumberFormatException ex){
				return null;
			}
		}
		String[] codeDistrict = multiParameters.get(AppConstant.DISTRICT);
		if(codeDistrict != null ){
			District district = districtService.getDistrictByCode(codeDistrict[0]);
			house.setDistrict(district);
			multiParameters.remove(AppConstant.DISTRICT);
		}
		String[] employee = multiParameters.get(AppConstant.EMPLOYEE);
		if(employee != null ){
			User user = usersService.getUserByUserName(employee[0]);
			house.setUser(user);
			multiParameters.remove(AppConstant.EMPLOYEE);
		}
		String[] monthsHire = multiParameters.get(AppConstant.MONTHSHIRE);
		if(monthsHire != null ){
			house.setMonthsHire(Integer.parseInt(monthsHire[0]));
			multiParameters.remove(AppConstant.MONTHSHIRE);
		}
		String[] rooms = multiParameters.get(AppConstant.ROOMS);
		if(rooms != null ){
			house.setRooms(Integer.parseInt(rooms[0]));
			multiParameters.remove(AppConstant.ROOMS);
		}
		String[] rentalCost = multiParameters.get(AppConstant.RENTALCOST);
		if(rentalCost != null ){
			String cost = rentalCost[0].replace(",", "");
			house.setRentalCost(Long.parseLong(cost));
			multiParameters.remove(AppConstant.RENTALCOST);
		}
		String[] codeHouse = multiParameters.get(AppConstant.CODEHOUSE);
		if(codeHouse != null ){
			house.setCodeHouse(codeHouse[0]);
			multiParameters.remove(AppConstant.CODEHOUSE);
		}
		String[] address = multiParameters.get(AppConstant.ADDRESS);
		if(address != null ){
			house.setAddress(address[0]);
			multiParameters.remove(AppConstant.ADDRESS);
		}
		String[] description = multiParameters.get(AppConstant.DESCRIPTION);
		if(description != null){
			house.setDescription(description[0]);
			multiParameters.remove(AppConstant.DESCRIPTION);
		}
		
		// set status to true
		house.setStatus(Boolean.valueOf("true"));
		house.setIsDisplay(Boolean.valueOf("false"));
		return house;
	}
	
	private List<Utility> setUtilities(Map<String, String[]> multiParameters){
		List<Utility> utilities = new ArrayList<Utility>();
		for(String value : multiParameters.keySet()) {
			if(value != null && multiParameters.get(value)[0].equals("true")){
				Utility utility = utilityService.getUtilityByCode(value);
				utilities.add(utility);
			}
		}
		return utilities;
	}
	
	/* merge utility house with house_utility*/
	private List<Utility> combineUtility(
			List<Utility> listUtility, List<Object[]> houseUtilities) {
		List<Utility> resultCombine = new ArrayList<Utility>();
		if(listUtility != null && listUtility.size() > 0){
			// create list dto => attribute + value
			for (Utility utility : listUtility) {
				if(houseUtilities.size() > 0){
					for(int i = 0; i< houseUtilities.size(); i++){
						if(utility.getCodeUtility().equals(houseUtilities.get(i)[2])){
							Utility dto = new Utility();
							dto.setCodeUtility(utility.getCodeUtility());
							dto.setNameUtility(utility.getNameUtility());
							dto.setStatus(Boolean.valueOf("true"));
							resultCombine.add(dto);
							break;
						}
						if(i == houseUtilities.size() - 1){
							Utility dto = new Utility();
							dto.setCodeUtility(utility.getCodeUtility());
							dto.setNameUtility(utility.getNameUtility());
							dto.setStatus(Boolean.valueOf("false"));
							resultCombine.add(dto);
						}
					}
				}else{
					Utility dto = new Utility();
					dto.setCodeUtility(utility.getCodeUtility());
					dto.setNameUtility(utility.getNameUtility());
					dto.setStatus(Boolean.valueOf("false"));
					resultCombine.add(dto);
				}
			}
		}
		return resultCombine;
	}
	
	/**
	 * Mark house to make plash
	 * @param request
	 * @return
	 */
	@RequestMapping(value = "/setDisplayCavas", method = RequestMethod.POST)
    public @ResponseBody String setDisplayCavas(HttpServletRequest request) {
    	List<Long> listLongId = new ArrayList<Long>();
    	Map<String, String[]> multiParameters = request.getParameterMap();
    	String[] listIdHouses = multiParameters.get("listIdHouses");
    	if(listIdHouses != null){
    		String[] listIdHousesValue = listIdHouses[0].split(",");
    		try{
    			for(int i = 0; i < listIdHousesValue.length; i++){
    				Long idNews = Long.parseLong(listIdHousesValue[i]);
    				listLongId.add(idNews);
    			}
    			Parameter parameter = parameterService.getParameterByCode(AppConstant.HOUSES_CODE);
    			if(listLongId.size() > 0 && parameter.getValue() >= listLongId.size()){
    				houseService.setDisplayCavas(listLongId);
    			}else if(listLongId.size() > 0){
    				return "fail";
    			}
    		}catch(NumberFormatException exception){
    			return "fail";
    		}
    	}
    	return "success";
    }
	
	// mark image to display on the cavas
 	@RequestMapping(value = "/markImage/{houseId}", method = RequestMethod.GET)
 	public ModelAndView markImage(@PathVariable Long houseId){
		House house = houseService.findHouseById(houseId);
		ModelAndView model = new ModelAndView("/admin/houses/markImages");
		model.addObject("house", house);
		return model;
 	}
 	
 	// getData mark image to display on the cavas
  	@RequestMapping(value = "/markImage/getData", method = RequestMethod.GET)
  	public @ResponseBody List<Image> markImageGetData(HttpServletRequest request){
  		String[] houseIdValue = request.getParameterMap().get("houseId");
  		Long houseId = Long.parseLong(houseIdValue[0]);
  		List<Image> images = imageService.getListImageByAId(houseId, AppConstant.HOUSES_CODE);
		
		if(images != null && images.size() > 0){
			for(Image image: images){
				image.setUrl("/" + AppConstant.APP_URL + "/admin/picture/"+ image.getId());
	            image.setThumbnailUrl("/" + AppConstant.APP_URL + "/admin/thumbnail/"+ image.getId());
	            image.setHouse(null);
			}
		}
 		return images;
  	}
 	
 	@RequestMapping(value = "/markImageFormSubmit", method = RequestMethod.POST)
 	public @ResponseBody String markImageFormSubmit(HttpServletRequest request){
 		Map<String, String[]> multiParameters = request.getParameterMap();
 		// merge product and attribute;
 		if(multiParameters.get("imageId")[0] != null){
 			// set only one image display = true and all false
 			imageService.markImageFormSubmit(Long.parseLong(multiParameters.get("imageId")[0]), AppConstant.HOUSES_CODE);
 			return "success";
 		}
 		return "fail";
 	}
 	
 	@RequestMapping(value = "/addDescriptionImages", method = RequestMethod.GET, produces="text/html; charset=utf-8")
	public ModelAndView addDescriptionImages(@RequestParam(value="houseId") String houseId) {
		ModelAndView model = new ModelAndView("admin/houses/addDescriptionImages");
		House house = houseService.findHouseById(Long.parseLong(houseId));
		model.addObject("houseId", house.getIdHouse());
		model.addObject("houseName", house.getNameHouse());
		
		List<Image> images = imageService.getAllImagesByHouseId(Long.parseLong(houseId));
		
		if(images != null && images.size() > 0){
			for(Image image: images){
	            image.setThumbnailUrl("/" + AppConstant.APP_URL + "/admin/thumbnail/"+ image.getId());
	            image.setHouse(null);
			}
		}
		model.addObject("images", images);
		return model;
	}
}
